"""
Radar Client

主要的雷达客户端类
"""

import logging
import time
import threading
from typing import List, Dict, Any, Optional, Callable
from .config import RadarConfig
from .interfaces import RadarInterface, RJ45Interface, RS232Interface
from .protocol import RadarPacket, RadarTarget, RadarStatus
from .exceptions import (
    RadarClientError, RadarConnectionError, RadarProtocolError,
    RadarTimeoutError, RadarCommandError
)


class RadarClient:
    """雷达客户端主类"""

    def __init__(self, config: Optional[Dict[str, Any]] = None, config_file: Optional[str] = None):
        """
        初始化雷达客户端

        Args:
            config: 配置字典
            config_file: 配置文件路径
        """
        self.config_manager = RadarConfig(config_file)
        self.interface: Optional[RadarInterface] = None
        self.interface_type: Optional[str] = None
        self.is_connected = False
        self._setup_logging()

        # 回调函数
        self._data_callback: Optional[Callable[[bytes], None]] = None
        self._target_callback: Optional[Callable[[List[RadarTarget]], None]] = None
        self._status_callback: Optional[Callable[[RadarStatus], None]] = None
        self._error_callback: Optional[Callable[[Exception], None]] = None

        # 线程控制
        self._heartbeat_thread: Optional[threading.Thread] = None
        self._stop_heartbeat = False

        # 更新配置
        if config:
            self.update_config(config)

    def _setup_logging(self) -> None:
        """设置日志"""
        general_config = self.config_manager.get_general_config()
        if general_config.get('enable_logging', True):
            logging.basicConfig(
                level=getattr(logging, general_config.get('log_level', 'INFO')),
                format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
            )
        self.logger = logging.getLogger('RadarClient')

    def connect_rj45(self, config: Optional[Dict[str, Any]] = None) -> None:
        """
        连接RJ45接口

        Args:
            config: RJ45配置，如果为None则使用默认配置
        """
        try:
            # 断开现有连接
            self.disconnect()

            # 获取配置
            if config:
                rj45_config = {**self.config_manager.get_rj45_config(), **config}
            else:
                rj45_config = self.config_manager.get_rj45_config()

            # 创建接口
            self.interface = RJ45Interface(rj45_config)
            self.interface_type = 'rj45'

            # 设置数据回调
            if self._data_callback:
                self.interface.set_data_callback(self._data_callback)

            # 连接
            self.interface.connect()
            self.is_connected = True

            # 启动心跳
            self._start_heartbeat()

            self.logger.info(f"RJ45连接成功: {rj45_config['ip_address']}:{rj45_config['data_port']}")

        except Exception as e:
            self.logger.error(f"RJ45连接失败: {e}")
            raise RadarConnectionError(f"RJ45连接失败: {e}")

    def connect_rs232(self, config: Optional[Dict[str, Any]] = None) -> None:
        """
        连接RS232接口

        Args:
            config: RS232配置，如果为None则使用默认配置
        """
        try:
            # 断开现有连接
            self.disconnect()

            # 获取配置
            if config:
                rs232_config = {**self.config_manager.get_rs232_config(), **config}
            else:
                rs232_config = self.config_manager.get_rs232_config()

            # 创建接口
            self.interface = RS232Interface(rs232_config)
            self.interface_type = 'rs232'

            # 设置数据回调
            if self._data_callback:
                self.interface.set_data_callback(self._data_callback)

            # 连接
            self.interface.connect()
            self.is_connected = True

            # 启动心跳
            self._start_heartbeat()

            self.logger.info(f"RS232连接成功: {rs232_config['port']}")

        except Exception as e:
            self.logger.error(f"RS232连接失败: {e}")
            raise RadarConnectionError(f"RS232连接失败: {e}")

    def disconnect(self) -> None:
        """断开连接"""
        # 停止心跳
        self._stop_heartbeat = True
        if self._heartbeat_thread and self._heartbeat_thread.is_alive():
            self._heartbeat_thread.join(timeout=2)

        # 断开接口
        if self.interface:
            self.interface.disconnect()
            self.interface = None

        self.is_connected = False
        self.interface_type = None
        self.logger.info("连接已断开")

    def send_command(self, command: int, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
        """
        发送命令

        Args:
            command: 命令代码
            params: 命令参数

        Returns:
            响应数据
        """
        if not self.is_connected or not self.interface:
            raise RadarConnectionError("未连接到雷达设备")

        try:
            # 创建命令包
            command_packet = RadarPacket.create_command_packet(
                command, params, self.interface_type
            )

            # 发送命令
            response_data = self.interface.send_command(
                command_packet,
                timeout=self.config_manager.get_general_config().get('command_timeout', 2000)
            )

            # 解析响应
            status, data = RadarPacket.parse_response_packet(response_data, self.interface_type)

            if status != RadarPacket.STATUS_SUCCESS:
                raise RadarCommandError(f"命令执行失败: {RadarPacket.get_status_name(status)}")

            return {
                'status': status,
                'data': data,
                'command': command
            }

        except Exception as e:
            self.logger.error(f"发送命令失败: {e}")
            if self._error_callback:
                self._error_callback(e)
            raise RadarClientError(f"发送命令失败: {e}")

    def start_scan(self) -> Dict[str, Any]:
        """启动雷达扫描"""
        return self.send_command(RadarPacket.CMD_START_SCAN)

    def stop_scan(self) -> Dict[str, Any]:
        """停止雷达扫描"""
        return self.send_command(RadarPacket.CMD_STOP_SCAN)

    def get_status(self) -> RadarStatus:
        """获取雷达状态"""
        try:
            response = self.send_command(RadarPacket.CMD_GET_STATUS)
            return RadarPacket.parse_status_data(response['data'])
        except Exception as e:
            self.logger.error(f"获取状态失败: {e}")
            raise RadarClientError(f"获取状态失败: {e}")

    def get_targets(self) -> List[RadarTarget]:
        """获取目标数据"""
        try:
            response = self.send_command(RadarPacket.CMD_GET_TARGETS)
            return RadarPacket.parse_targets_data(response['data'])
        except Exception as e:
            self.logger.error(f"获取目标数据失败: {e}")
            raise RadarClientError(f"获取目标数据失败: {e}")

    def reset_radar(self) -> Dict[str, Any]:
        """重置雷达系统"""
        return self.send_command(RadarPacket.CMD_RESET)

    def configure_radar(self, config: Dict[str, Any]) -> Dict[str, Any]:
        """
        配置雷达参数

        Args:
            config: 雷达配置参数

        Returns:
            配置结果
        """
        return self.send_command(RadarPacket.CMD_CONFIG, config)

    def set_data_callback(self, callback: Callable[[bytes], None]) -> None:
        """设置数据接收回调"""
        self._data_callback = callback
        if self.interface:
            self.interface.set_data_callback(callback)

    def set_target_callback(self, callback: Callable[[List[RadarTarget]], None]) -> None:
        """设置目标数据回调"""
        self._target_callback = callback

    def set_status_callback(self, callback: Callable[[RadarStatus], None]) -> None:
        """设置状态数据回调"""
        self._status_callback = callback

    def set_error_callback(self, callback: Callable[[Exception], None]) -> None:
        """设置错误回调"""
        self._error_callback = callback

    def _start_heartbeat(self) -> None:
        """启动心跳线程"""
        self._stop_heartbeat = False
        self._heartbeat_thread = threading.Thread(target=self._heartbeat_loop, daemon=True)
        self._heartbeat_thread.start()

    def _heartbeat_loop(self) -> None:
        """心跳循环"""
        interval = self.config_manager.get_general_config().get('heartbeat_interval', 5000) / 1000

        while not self._stop_heartbeat and self.is_connected:
            try:
                time.sleep(interval)
                if not self._stop_heartbeat and self.is_connected:
                    # 发送心跳命令（获取状态）
                    status = self.get_status()
                    if self._status_callback:
                        self._status_callback(status)
            except Exception as e:
                self.logger.warning(f"心跳失败: {e}")
                if self._error_callback:
                    self._error_callback(e)

                # 自动重连
                if self.config_manager.get_general_config().get('auto_reconnect', True):
                    try:
                        self.disconnect()
                        time.sleep(1)
                        if self.interface_type == 'rj45':
                            self.connect_rj45()
                        elif self.interface_type == 'rs232':
                            self.connect_rs232()
                    except Exception as reconnect_error:
                        self.logger.error(f"重连失败: {reconnect_error}")

    def get_connection_info(self) -> Dict[str, Any]:
        """获取连接信息"""
        if self.interface:
            return self.interface.get_connection_info()
        return {
            'is_connected': self.is_connected,
            'interface_type': self.interface_type
        }

    def update_config(self, config: Dict[str, Any]) -> None:
        """更新配置"""
        for section, section_config in config.items():
            for key, value in section_config.items():
                self.config_manager.update_config(section, key, value)

    def save_config(self, file_path: Optional[str] = None) -> None:
        """保存配置"""
        self.config_manager.save_config(file_path)

    def __enter__(self):
        """上下文管理器支持"""
        return self

    def __exit__(self, exc_type, exc_val, exc_tb):
        """上下文管理器支持"""
        self.disconnect()

    def __str__(self) -> str:
        """字符串表示"""
        return f"RadarClient(interface_type={self.interface_type}, connected={self.is_connected})"